package com.jx.ui;

import com.jx.crack.util;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.math.BigInteger;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

public class Tools {

    // 需要patch的数据
    public static String e = "2ag0dj43je3oxf22utaopxp61jqgc2epo0drzxzsf3uc12i4kzru7v17z9mv954zr81m1yl0k1c07y9adyzteowk0yt8xdn01qvtamv6b360we9k0z5mqq670yxu3yu4e4vmflp18ie8ojq2nabd2qdjb6wuwoejtllllkkd8hh5tvlbgr65tps5bukokdni2c";
    // 需要patch的数据
    public static String f = "29suwrt1kkridgt5sm6a1pb4q0hiwa3nskk7hdsvqw2fikywu1vvyp69k3msaezzcwi2k17lx13tqcpko0gxq2p00rkwc00dzfh5b3cgqz9kgh8v2qhveb8iak1mzov5889ws3xha13p2ntsd8j1iw81esznyktx8t6ahz6vfpt2uw4hxegllgp5bdwyco1stu";
    // 未加密的情况
    public static String e1 = "33851717214292305582010417393402727812830176472733550790920844148355988054130010499992971193003524512509240474673101724848384";
    public static String f1 = "25667112684517379948185296389386925307782598673250742557116530456931377273936147127185145251019629808481495879454212767959902";

    // patch数据
    public static byte[] patch = {0x00, 0x02, 0x32, 0x31};
    // patch数据
    public static byte[] patch1 = {0x00, 0x01, 0x31};

    public static final HashMap<String, String> packages = new HashMap<String, String>() {
        private static final long serialVersionUID = -5323318496902313501L;

        {
            put("jxbrowser", "com/teamdev/jxbrowser/chromium/");
            put("jexplorer", "com/teamdev/jexplorer/");
            put("comfyj", "com/jniwrapper/win32/");
            put("jexcel", "com/jniwrapper/win32/jexcel/");
        }
    };

    /**
     * 从jar创建类加载器
     *
     * @param jar_path
     * @return
     */
    public static URLClassLoader getClassLoaderFromJar(ArrayList<File> jar_path) {
        //文件协议,Linux和Windows不同
        String protocol = isWindows() ? "file:/" : "file:";
        // 类加载器，用于从jar文件加载类
        URLClassLoader myClassLoader = null;
        // 初始化类加载器
        try {
            URL[] urls = new URL[jar_path.size()];
            for (int i = 0; i < jar_path.size(); i++) {
                urls[i] = new URL(protocol + jar_path.get(i).getAbsolutePath());
            }
            myClassLoader = new URLClassLoader(urls);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return myClassLoader;
    }

    /**
     * 反射查找证书验证类
     *
     * @param myClassLoader
     * @param soft_name
     * @param file
     * @return
     * @throws IOException
     */

    public static String getVertifyLicenceClass(URLClassLoader myClassLoader, String soft_name, File file) throws IOException {
        // jar文件
        JarFile jFile = new JarFile(file);
        // 类
        Class<?> cla = null;
        // 属性
        Field[] fields;
        // 类名
        String classname;
        // 比对的5个变量
        BigInteger b = new BigInteger("1");
        BigInteger c = new BigInteger("0");
        BigInteger d = new BigInteger(
                "34051811835788252902797885733156696286414897221750775263783399829125079614056933876807669964513495918712211128108375406963673");
        BigInteger e = new BigInteger(
                "33851717214292305582010417393402727812830176472733550790920844148355988054130010499992971193003524512509240474673101724848384");
        BigInteger f = new BigInteger(
                "25667112684517379948185296389386925307782598673250742557116530456931377273936147127185145251019629808481495879454212767959902");
        // 临时变量
        BigInteger tmp;

        // 从jar读取类
        Enumeration<JarEntry> entries = jFile.entries();
        while (entries.hasMoreElements()) {
            // 替换类的表示形式
            classname = entries.nextElement().getName();
            // 过滤类,只查找这个目录下的类，用到了java类的命名规则
            if (classname.matches(packages.get(soft_name) + "[A-Za-z0-9_]+\\.class")) {
                try {
                    // 加载类
                    cla = myClassLoader.loadClass(classname.replaceAll("/", "\\.").replaceAll(".class", ""));
                } catch (ClassNotFoundException exception) {
                    // 加载类出错则跳过本次循环
                    continue;
                }
                // 获取类属性
                fields = cla.getDeclaredFields();
                // 属性变量至少6个
                if (fields.length >= 6) {
                    // 计数变量
                    int i = 0;
                    // 属性变量需要5个都是BigInteger类型
                    for (Field field : fields) {
                        // BigInteger类型
                        if (field.getType().getName().equals("java.math.BigInteger")) {
                            // 设置属性可以访问
                            field.setAccessible(true);
                            try {
                                tmp = (BigInteger) field.get(null);
                            } catch (IllegalArgumentException | IllegalAccessException exception) {
                                continue;
                            }
                            if (tmp.compareTo(b) == 0 || tmp.compareTo(c) == 0 || tmp.compareTo(d) == 0
                                    || tmp.compareTo(e) == 0 || tmp.compareTo(f) == 0) {// 不通过字段名判断，字段名可能不一样，只通过数据匹配判断
                                i++;
                            }
                        }
                    }
                    // 需要5个
                    if (i == 5) {
                        // 查找到则返回
                        jFile.close();
                        return classname;
                    }
                }
            }
        }

        jFile.close();
        return null;
    }

    /**
     * 判断是否未Windows操作系统
     * @return
     */
    public static boolean isWindows() {
        if (System.getProperty("os.name").toLowerCase().startsWith("windows")) {
            return true;
        }
        return false;
    }

    /**
     * 计算patch后的数据
     *
     * @param is
     * @return
     * @throws IOException
     */
    public static byte[] patchData(InputStream is) throws IOException {
        // 内容是否加密,默认加密
        boolean flag = true;

        int count = is.available();
        byte[] data = new byte[count];
        is.read(data);

        HashMap<String, Integer> stringPos = analyClass(data);
        if (stringPos.get(e) == null || stringPos.get(f) == null) {// 查找加密的情况
            if (stringPos.get(e1) == null || stringPos.get(f1) == null) {// 查找未加密的情况
                return null;// 没有查找需要修改的属性，请确认是否已经破解。
            } else {
                flag = false;
            }
        }

        int[] index = new int[2];
        if (flag) {
            index[0] = stringPos.get(e);
            index[1] = stringPos.get(f);
        } else {
            index[0] = stringPos.get(e1);
            index[1] = stringPos.get(f1);
        }
        // 大数放在第一个，先处理大数，也就是在文件后部的数据
        if (index[0] < index[1]) {
            int tmp = index[0];
            index[0] = index[1];
            index[1] = tmp;
        }
        // e、f数据长度相同，加上2个字节长度,再减去替换的字节长度
        for (int i = 0; i < index.length; i++) {

            byte[] tmp;

            if (flag) {
                tmp = new byte[data.length - (e.length() + 2 - patch.length)];
            } else {
                tmp = new byte[data.length - (e1.length() + 2 - patch1.length)];
            }
            // 索引前的数据复制过去
            System.arraycopy(data, 0, tmp, 0, index[i]);
            // 复制补丁数据
            if (flag) {
                System.arraycopy(patch, 0, tmp, index[i], patch.length);
            } else {
                System.arraycopy(patch1, 0, tmp, index[i], patch1.length);
            }
            // 复制字段属性后面的数据
            if (flag) {
                System.arraycopy(data, index[i] + 2 + e.length(), tmp, index[i] + patch.length,
                        data.length - (index[i] + 2 + e.length()));
            } else {
                System.arraycopy(data, index[i] + 2 + e1.length(), tmp, index[i] + patch1.length,
                        data.length - (index[i] + 2 + e1.length()));
            }
            // data重新赋值
            data = tmp;
        }
        return data;
    }

    /**
     * 反编译查找属性值,具体class文件解析请见Test文件,这里只获取utf-8字符部分
     *
     * @param data
     */
    public static HashMap<String, Integer> analyClass(byte[] data) {
        HashMap<String, Integer> stringPos = new HashMap<>();

        byte[] tmp;
        // 跳过magic、minor_version、major_version
        int index = 4 + 2 + 2;

        tmp = util.buf_get_buf(data, index, 2);
        index += 2;
        int constant_pool_count = util.buf_to_int16(tmp, 0);

        int tag;
        for (int i = 1; i < constant_pool_count; i++) {

            tmp = util.buf_get_buf(data, index, 1);
            index += 1;
            tag = util.buf_to_int8(tmp, 0);
            // 只处理utf字符数据，其他只根据数据长度调整index
            switch (tag) {
                case 1:// CONSTANT_Utf8
                    tmp = util.buf_get_buf(data, index, 2);
                    index += 2;
                    int length = util.buf_to_int16(tmp, 0);

                    tmp = util.buf_get_buf(data, index, length);
                    index += length;
                    stringPos.put(new String(tmp), index - length - 2);
                    break;
                case 3:// CONSTANT_Integer
                    index += 2;
                    break;
                case 4:// CONSTANT_Float
                    index += 2;
                    break;
                case 5:// CONSTANT_Long
                    index += 2;
                    break;
                case 6:// CONSTANT_Double
                    index += 2;
                    break;
                case 7:// CONSTANT_Class
                    index += 2;
                    break;
                case 8:// CONSTANT_String
                    index += 2;
                    break;
                case 9:// CONSTANT_Fieldref
                    index += 4;
                    break;
                case 10:// CONSTANT_Methodref
                    index += 4;
                    break;
                case 11:// CONSTANT_InterfaceMethodref
                    index += 4;
                    break;
                case 12:// CONSTANT_NameAndType
                    index += 4;
                    break;
                case 15:// CONSTANT_MethodHandle
                    index += 2;
                    break;
                case 16:// CONSTANT_MethodType
                    index += 2;
                    break;
                case 18:// CONSTANT_InvokeDynamic
                    index += 2;
                    break;
                default:
                    break;
            }
        }
        // 后续数据不再分析
        return stringPos;
    }

}
